/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  md5.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2016/04/13
  *Desc		:  改自SSMD5.h,后续需要替换SSMD5.h的实现
  *Relation :
  *Others	:
  *Function :
  *History	:  1.极力减少头文件内容,尽可能移到CPP文件中,降低模块耦合度.by scofined.qi@sumscope.com,20160413
  2.增加MD5Impl类用于存储原先在文件作用域中的全局变量,
  避免多线程同时读写造成不稳定.by scofined.qi@sumscope.com,20160413
  ***************************************************************************************************/
#include "md5.h"
#include <string.h>
#include "../Utility.h"

#ifndef BASSERT
#define BASSERT //
#endif
#ifndef BLOGERR
#define BLOGERR //
#endif

namespace qb{
	namespace base{


		typedef unsigned       int uint4;
		typedef unsigned short int uint2;
		typedef unsigned      char uchar;

		inline uint4 rotate_left(uint4 x, uint4 n)
		{
			return ((x << n) | (x >> (32 - n)));
		}

		inline uint4 F(uint4 x, uint4 y, uint4 z)
		{
			return ((x & y) | (~x & z));
		}

		inline uint4 G(uint4 x, uint4 y, uint4 z)
		{
			return ((x & z) | (y & ~z));
		}

		inline uint4 H(uint4 x, uint4 y, uint4 z)
		{
			return (x ^ y ^ z);
		}

		inline uint4 I(uint4 x, uint4 y, uint4 z)
		{
			return (y ^ (x | ~z));
		}

		inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
		{
			a += F(b, c, d) + x + ac; a = rotate_left(a, s); a += b;
		}

		inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
		{
			a += G(b, c, d) + x + ac; a = rotate_left(a, s); a += b;
		}

		inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
		{
			a += H(b, c, d) + x + ac; a = rotate_left(a, s); a += b;
		}

		inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
		{
			a += I(b, c, d) + x + ac; a = rotate_left(a, s); a += b;
		}

		static unsigned char PADDING[64] =
		{
			0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
		};

#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

		class MD5Impl{
			uint4    m_State[4];
			uint4    m_Count[2];
			uchar    m_Buffer[64];
			uchar    m_Digest[16];
			uchar    m_Finalized;
		public:
			MD5Impl() :m_Finalized(0)
			{
				memset(m_Digest, 0, 16 * sizeof(uchar));
				memset(m_Buffer, 0, 64 * sizeof(uchar));
				Init();
			}
			char* PrintMD5(uchar md5Digest[16]);
			char* MD5String(const char* szString);
			char* MD5String(const char* szString,int szStrLen);
			char* MD5File(const char* szFilename);

		protected:
			void Init();
			void Update(uchar* chInput, uint4 nInputLen);
			void Finalize();
			uchar* Digest();// { return m_Digest; }

			void Transform(uchar* block);
			void Encode(uchar* dest, uint4* src, uint4 nLength);
			void Decode(uint4* dest, uchar* src, uint4 nLength);
		};

		char* MD5Impl::PrintMD5(uchar md5Digest[16])
		{
			char chBuffer[256] = { 0 };
			char chEach[10] = { 0 };
			int nCount;

			memset(chBuffer, 0, 256);
			memset(chEach, 0, 10);

			for (nCount = 0; nCount < 16; nCount++)
			{
				FMTBUF(chEach, "%02x", md5Digest[nCount]);
				strncat(chBuffer, chEach, sizeof(chEach));
			}

            return strdup(chBuffer);
		}

		char* MD5Impl::MD5String(const char* szString)
		{
			Init();
			int nLen = strlen(szString);
			Update((unsigned char*)szString, (unsigned int)nLen);
			Finalize();

			return PrintMD5(Digest());

		}
		char* MD5Impl::MD5String(const char* szString, int szStrLen)
		{
			Init();
			Update((unsigned char*)szString, (unsigned int)szStrLen);
			Finalize();
			return PrintMD5(Digest());
		}
		char* MD5Impl::MD5File(const char* szFilename)
		{
			FILE* file;
			int nLen;
			unsigned char chBuffer[1024] = { 0 };

			try
			{
				memset(chBuffer, 0, 1024);

				if ((file = fopen(szFilename, "rb")) != NULL)
				{
					while (nLen = fread(chBuffer, 1, 1024, file))
						Update(chBuffer, nLen);

					Finalize();

					fclose(file);

					return PrintMD5(Digest());
				}
			}
			catch (...)
			{

			}

			return NULL; // failed
		}

		void MD5Impl::Init()
		{
			memset(m_Count, 0, 2 * sizeof(uint4));

			m_State[0] = 0x67452301;
			m_State[1] = 0xefcdab89;
			m_State[2] = 0x98badcfe;
			m_State[3] = 0x10325476;
		}

		void MD5Impl::Update(uchar* chInput, uint4 nInputLen)
		{
			uint4 i, index, partLen;

			// Compute number of bytes mod 64
			index = (unsigned int)((m_Count[0] >> 3) & 0x3F);

			// Update number of bits
			if ((m_Count[0] += (nInputLen << 3)) < (nInputLen << 3))
				m_Count[1]++;

			m_Count[1] += (nInputLen >> 29);

			partLen = 64 - index;

			// Transform as many times as possible.
			if (nInputLen >= partLen)
			{
				memcpy(&m_Buffer[index], chInput, partLen);
				Transform(m_Buffer);

				for (i = partLen; i + 63 < nInputLen; i += 64)
					Transform(&chInput[i]);

				index = 0;
			}
			else
				i = 0;

			// Buffer remaining input
			memcpy(&m_Buffer[index], &chInput[i], nInputLen - i);
		}

		void MD5Impl::Finalize()
		{
			uchar bits[8] = { 0 };
			uint4 index, padLen;

			// Save number of bits
			Encode(bits, m_Count, 8);

			// Pad out to 56 mod 64
			index = (unsigned int)((m_Count[0] >> 3) & 0x3f);
			padLen = (index < 56) ? (56 - index) : (120 - index);
			Update(PADDING, padLen);

			// Append length (before padding)
			Update(bits, 8);

			// Store state in digest
			Encode(m_Digest, m_State, 16);

			memset(m_Count, 0, 2 * sizeof(uint4));
			memset(m_State, 0, 4 * sizeof(uint4));
			memset(m_Buffer, 0, 64 * sizeof(uchar));
		}

		uchar* MD5Impl::Digest()
		{
			return m_Digest;
		}

		void MD5Impl::Transform(uchar* block)
		{
			uint4 a = m_State[0], b = m_State[1], c = m_State[2], d = m_State[3], x[16];

			Decode(x, block, 64);

			// Round 1
			FF(a, b, c, d, x[0], S11, 0xd76aa478);
			FF(d, a, b, c, x[1], S12, 0xe8c7b756);
			FF(c, d, a, b, x[2], S13, 0x242070db);
			FF(b, c, d, a, x[3], S14, 0xc1bdceee);
			FF(a, b, c, d, x[4], S11, 0xf57c0faf);
			FF(d, a, b, c, x[5], S12, 0x4787c62a);
			FF(c, d, a, b, x[6], S13, 0xa8304613);
			FF(b, c, d, a, x[7], S14, 0xfd469501);
			FF(a, b, c, d, x[8], S11, 0x698098d8);
			FF(d, a, b, c, x[9], S12, 0x8b44f7af);
			FF(c, d, a, b, x[10], S13, 0xffff5bb1);
			FF(b, c, d, a, x[11], S14, 0x895cd7be);
			FF(a, b, c, d, x[12], S11, 0x6b901122);
			FF(d, a, b, c, x[13], S12, 0xfd987193);
			FF(c, d, a, b, x[14], S13, 0xa679438e);
			FF(b, c, d, a, x[15], S14, 0x49b40821);

			// Round 2
			GG(a, b, c, d, x[1], S21, 0xf61e2562);
			GG(d, a, b, c, x[6], S22, 0xc040b340);
			GG(c, d, a, b, x[11], S23, 0x265e5a51);
			GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);
			GG(a, b, c, d, x[5], S21, 0xd62f105d);
			GG(d, a, b, c, x[10], S22, 0x2441453);
			GG(c, d, a, b, x[15], S23, 0xd8a1e681);
			GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);
			GG(a, b, c, d, x[9], S21, 0x21e1cde6);
			GG(d, a, b, c, x[14], S22, 0xc33707d6);
			GG(c, d, a, b, x[3], S23, 0xf4d50d87);
			GG(b, c, d, a, x[8], S24, 0x455a14ed);
			GG(a, b, c, d, x[13], S21, 0xa9e3e905);
			GG(d, a, b, c, x[2], S22, 0xfcefa3f8);
			GG(c, d, a, b, x[7], S23, 0x676f02d9);
			GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);

			// Round 3
			HH(a, b, c, d, x[5], S31, 0xfffa3942);
			HH(d, a, b, c, x[8], S32, 0x8771f681);
			HH(c, d, a, b, x[11], S33, 0x6d9d6122);
			HH(b, c, d, a, x[14], S34, 0xfde5380c);
			HH(a, b, c, d, x[1], S31, 0xa4beea44);
			HH(d, a, b, c, x[4], S32, 0x4bdecfa9);
			HH(c, d, a, b, x[7], S33, 0xf6bb4b60);
			HH(b, c, d, a, x[10], S34, 0xbebfbc70);
			HH(a, b, c, d, x[13], S31, 0x289b7ec6);
			HH(d, a, b, c, x[0], S32, 0xeaa127fa);
			HH(c, d, a, b, x[3], S33, 0xd4ef3085);
			HH(b, c, d, a, x[6], S34, 0x4881d05);
			HH(a, b, c, d, x[9], S31, 0xd9d4d039);
			HH(d, a, b, c, x[12], S32, 0xe6db99e5);
			HH(c, d, a, b, x[15], S33, 0x1fa27cf8);
			HH(b, c, d, a, x[2], S34, 0xc4ac5665);

			// Round 4
			II(a, b, c, d, x[0], S41, 0xf4292244);
			II(d, a, b, c, x[7], S42, 0x432aff97);
			II(c, d, a, b, x[14], S43, 0xab9423a7);
			II(b, c, d, a, x[5], S44, 0xfc93a039);
			II(a, b, c, d, x[12], S41, 0x655b59c3);
			II(d, a, b, c, x[3], S42, 0x8f0ccc92);
			II(c, d, a, b, x[10], S43, 0xffeff47d);
			II(b, c, d, a, x[1], S44, 0x85845dd1);
			II(a, b, c, d, x[8], S41, 0x6fa87e4f);
			II(d, a, b, c, x[15], S42, 0xfe2ce6e0);
			II(c, d, a, b, x[6], S43, 0xa3014314);
			II(b, c, d, a, x[13], S44, 0x4e0811a1);
			II(a, b, c, d, x[4], S41, 0xf7537e82);
			II(d, a, b, c, x[11], S42, 0xbd3af235);
			II(c, d, a, b, x[2], S43, 0x2ad7d2bb);
			II(b, c, d, a, x[9], S44, 0xeb86d391);

			m_State[0] += a;
			m_State[1] += b;
			m_State[2] += c;
			m_State[3] += d;

			memset(x, 0, sizeof(x));
		}

		void MD5Impl::Encode(uchar* dest, uint4* src, uint4 nLength)
		{
			uint4 i, j;

			BASSERT(nLength % 4 == 0);

			for (i = 0, j = 0; j < nLength; i++, j += 4)
			{
				dest[j] = (uchar)(src[i] & 0xff);
				dest[j + 1] = (uchar)((src[i] >> 8) & 0xff);
				dest[j + 2] = (uchar)((src[i] >> 16) & 0xff);
				dest[j + 3] = (uchar)((src[i] >> 24) & 0xff);
			}
		}

		void MD5Impl::Decode(uint4* dest, uchar* src, uint4 nLength)
		{
			uint4 i, j;

			BASSERT(nLength % 4 == 0);

			for (i = 0, j = 0; j < nLength; i++, j += 4)
			{
				dest[i] = ((uint4)src[j]) | (((uint4)src[j + 1]) << 8) |
					(((uint4)src[j + 2]) << 16) | (((uint4)src[j + 3]) << 24);
			}
		}

		bool MD5::FromString(const char* szStr, int szStrLen, char* md5buf, int len)
		{
			if (szStr == 0 || md5buf == 0 || len <= 32 || szStrLen<=0)
			{
				BLOGERR("[MD5]invalid argument");
				return false;
			}
			MD5Impl md5i;
			char* md5str = md5i.MD5String(szStr,szStrLen);
			bool succeed = false;
			if (md5str)
			{
				int md5len = strlen(md5str);
				if (md5len < len)
				{
					succeed = FIELDCOPYN(md5buf, len, md5str) == 32;
				}
				free(md5str);
			}
			return succeed;
		}
		bool MD5::FromString(const char* szStr, char* md5buf, int len)
		{
			if (szStr == 0 || md5buf == 0 || len <= 32)
			{
				BLOGERR("[MD5]invalid argument");
				return false;
			}
			MD5Impl md5i;
			char* md5str = md5i.MD5String(szStr);
			bool succeed = false;
			if (md5str)
			{
				int md5len = strlen(md5str);
				if (md5len < len)
				{
					succeed = FIELDCOPYN(md5buf, len, md5str) == 32;
				}
				free(md5str);
			}
			return succeed;
		}
		bool MD5::FromFile(const char* szFileName, char* md5buf, int len)
		{
			if (szFileName == 0 || md5buf == 0 || len <= 32)
			{
				BLOGERR("[MD5]invalid argument");
				return false;
			}
			MD5Impl md5i;
			char* md5str = md5i.MD5File(szFileName);
			bool succeed = false;
			if (md5str)
			{
				int md5len = strlen(md5str);
				if (md5len < len)
				{
					succeed = FIELDCOPYN(md5buf, len, md5str) == 32;
				}
				free(md5str);
			}
			return succeed;
		}
	}

    #define S11 7
    #define S12 12
    #define S13 17
    #define S14 22
    #define S21 5
    #define S22 9
    #define S23 14
    #define S24 20
    #define S31 4
    #define S32 11
    #define S33 16
    #define S34 23
    #define S41 6
    #define S42 10
    #define S43 15
    #define S44 21

    uint4    m_State[4] = { 0 };
    uint4    m_Count[2] = { 0 };
    uchar    m_Buffer[64] = { 0 };
    uchar    m_Digest[16] = { 0 };
    uchar    m_Finalized;

    char* PrintMD5(uchar md5Digest[16])
    {
        char chBuffer[256] = { 0 };
        char chEach[10] = { 0 };
        int nCount;

        memset(chBuffer,0,256);
        memset(chEach, 0, 10);

        int len = 0;
        for (nCount = 0; nCount < 16; nCount++)
        {
            sprintf(chEach, "%02x", md5Digest[nCount]);
            len = sizeof(chEach);
            strncat(chBuffer, chEach, len);
        }

        return strdup(chBuffer);
    }

    char* MD5String(const char* szString)
    {
        Init();
        int nLen = strlen(szString);
        Update((unsigned char*)szString, (unsigned int)nLen);
        Finalize();

        return PrintMD5(Digest());

    }
    char* MD5File(char* szFilename)
    {
        FILE* file;
        int nLen;
        unsigned char chBuffer[1024] = { 0 };

        //try
        {
            memset(chBuffer, 0, 1024);

            if ((file = fopen (szFilename, "rb")) != NULL)
            {
                while(1)
                {
                    nLen = fread (chBuffer, 1, 1024, file);
                    if (nLen <= 0)
                    {
                        break;
                    }

                    Update(chBuffer, nLen);
                }

                Finalize();

                fclose (file);

                return PrintMD5(Digest());
            }
        }
        //catch(...)
        {

        }

        return NULL; // failed
    }

    void Init()
    {
        memset(m_Count, 0, 2 * sizeof(uint4));

        m_State[0] = 0x67452301;
        m_State[1] = 0xefcdab89;
        m_State[2] = 0x98badcfe;
        m_State[3] = 0x10325476;
    }

    void Update(uchar* chInput, uint4 nInputLen)
    {
        uint4 i, index, partLen;

        // Compute number of bytes mod 64
        index = (unsigned int)((m_Count[0] >> 3) & 0x3F);

        // Update number of bits
        if ((m_Count[0] += (nInputLen << 3)) < (nInputLen << 3))
            m_Count[1]++;

        m_Count[1] += (nInputLen >> 29);

        partLen = 64 - index;

        // Transform as many times as possible.
        if (nInputLen >= partLen)
        {
            memcpy( &m_Buffer[index], chInput, partLen );
            Transform(m_Buffer);

            for (i = partLen; i + 63 < nInputLen; i += 64)
                Transform(&chInput[i]);

            index = 0;
        }
        else
            i = 0;

        // Buffer remaining input
        memcpy( &m_Buffer[index], &chInput[i], nInputLen-i );
    }

    void Finalize()
    {
        uchar bits[8] = { 0 };
        uint4 index, padLen;

        // Save number of bits
        Encode (bits, m_Count, 8);

        // Pad out to 56 mod 64
        index = (unsigned int)((m_Count[0] >> 3) & 0x3f);
        padLen = (index < 56) ? (56 - index) : (120 - index);
        Update(PADDING, padLen);

        // Append length (before padding)
        Update (bits, 8);

        // Store state in digest
        Encode (m_Digest, m_State, 16);

        memset(m_Count, 0, 2 * sizeof(uint4));
        memset(m_State, 0, 4 * sizeof(uint4));
        memset(m_Buffer,0, 64 * sizeof(uchar));
    }

    uchar* Digest()
    {
        return m_Digest;
    }

    void Transform (uchar* block)
    {
        uint4 a = m_State[0], b = m_State[1], c = m_State[2], d = m_State[3], x[16];

        Decode (x, block, 64);

        // Round 1
        FF (a, b, c, d, x[ 0], S11, 0xd76aa478);
        FF (d, a, b, c, x[ 1], S12, 0xe8c7b756);
        FF (c, d, a, b, x[ 2], S13, 0x242070db);
        FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
        FF (a, b, c, d, x[ 4], S11, 0xf57c0faf);
        FF (d, a, b, c, x[ 5], S12, 0x4787c62a);
        FF (c, d, a, b, x[ 6], S13, 0xa8304613);
        FF (b, c, d, a, x[ 7], S14, 0xfd469501);
        FF (a, b, c, d, x[ 8], S11, 0x698098d8);
        FF (d, a, b, c, x[ 9], S12, 0x8b44f7af);
        FF (c, d, a, b, x[10], S13, 0xffff5bb1);
        FF (b, c, d, a, x[11], S14, 0x895cd7be);
        FF (a, b, c, d, x[12], S11, 0x6b901122);
        FF (d, a, b, c, x[13], S12, 0xfd987193);
        FF (c, d, a, b, x[14], S13, 0xa679438e);
        FF (b, c, d, a, x[15], S14, 0x49b40821);

        // Round 2
        GG (a, b, c, d, x[ 1], S21, 0xf61e2562);
        GG (d, a, b, c, x[ 6], S22, 0xc040b340);
        GG (c, d, a, b, x[11], S23, 0x265e5a51);
        GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
        GG (a, b, c, d, x[ 5], S21, 0xd62f105d);
        GG (d, a, b, c, x[10], S22, 0x2441453);
        GG (c, d, a, b, x[15], S23, 0xd8a1e681);
        GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8);
        GG (a, b, c, d, x[ 9], S21, 0x21e1cde6);
        GG (d, a, b, c, x[14], S22, 0xc33707d6);
        GG (c, d, a, b, x[ 3], S23, 0xf4d50d87);
        GG (b, c, d, a, x[ 8], S24, 0x455a14ed);
        GG (a, b, c, d, x[13], S21, 0xa9e3e905);
        GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8);
        GG (c, d, a, b, x[ 7], S23, 0x676f02d9);
        GG (b, c, d, a, x[12], S24, 0x8d2a4c8a);

        // Round 3
        HH (a, b, c, d, x[ 5], S31, 0xfffa3942);
        HH (d, a, b, c, x[ 8], S32, 0x8771f681);
        HH (c, d, a, b, x[11], S33, 0x6d9d6122);
        HH (b, c, d, a, x[14], S34, 0xfde5380c);
        HH (a, b, c, d, x[ 1], S31, 0xa4beea44);
        HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9);
        HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60);
        HH (b, c, d, a, x[10], S34, 0xbebfbc70);
        HH (a, b, c, d, x[13], S31, 0x289b7ec6);
        HH (d, a, b, c, x[ 0], S32, 0xeaa127fa);
        HH (c, d, a, b, x[ 3], S33, 0xd4ef3085);
        HH (b, c, d, a, x[ 6], S34, 0x4881d05);
        HH (a, b, c, d, x[ 9], S31, 0xd9d4d039);
        HH (d, a, b, c, x[12], S32, 0xe6db99e5);
        HH (c, d, a, b, x[15], S33, 0x1fa27cf8);
        HH (b, c, d, a, x[ 2], S34, 0xc4ac5665);

        // Round 4
        II (a, b, c, d, x[ 0], S41, 0xf4292244);
        II (d, a, b, c, x[ 7], S42, 0x432aff97);
        II (c, d, a, b, x[14], S43, 0xab9423a7);
        II (b, c, d, a, x[ 5], S44, 0xfc93a039);
        II (a, b, c, d, x[12], S41, 0x655b59c3);
        II (d, a, b, c, x[ 3], S42, 0x8f0ccc92);
        II (c, d, a, b, x[10], S43, 0xffeff47d);
        II (b, c, d, a, x[ 1], S44, 0x85845dd1);
        II (a, b, c, d, x[ 8], S41, 0x6fa87e4f);
        II (d, a, b, c, x[15], S42, 0xfe2ce6e0);
        II (c, d, a, b, x[ 6], S43, 0xa3014314);
        II (b, c, d, a, x[13], S44, 0x4e0811a1);
        II (a, b, c, d, x[ 4], S41, 0xf7537e82);
        II (d, a, b, c, x[11], S42, 0xbd3af235);
        II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb);
        II (b, c, d, a, x[ 9], S44, 0xeb86d391);

        m_State[0] += a;
        m_State[1] += b;
        m_State[2] += c;
        m_State[3] += d;

        memset(x, 0, sizeof(x));
    }

    void Encode(uchar* dest, uint4* src, uint4 nLength)
    {
        uint4 i, j;

        assert(nLength % 4 == 0);

        for (i = 0, j = 0; j < nLength; i++, j += 4)
        {
            dest[j] = (uchar)(src[i] & 0xff);
            dest[j+1] = (uchar)((src[i] >> 8) & 0xff);
            dest[j+2] = (uchar)((src[i] >> 16) & 0xff);
            dest[j+3] = (uchar)((src[i] >> 24) & 0xff);
        }
    }

    void Decode(uint4* dest, uchar* src, uint4 nLength)
    {
        uint4 i, j;

        assert(nLength % 4 == 0);

        for (i = 0, j = 0; j < nLength; i++, j += 4)
        {
            dest[i] = ((uint4)src[j]) | (((uint4)src[j+1])<<8) |
                (((uint4)src[j+2])<<16) | (((uint4)src[j+3])<<24);
        }
    }
}
